require 'digest/md5'
require 'open-uri'
require 'rexml/document'
require 'cgi'

def remove_newline(s)
  return s.gsub("\n", "")
end

def save_map(filename, map, sp)
  File.open(filename, 'w') do |f|
    map.each do |k, v|
      f.write("#{k}#{sp}#{v}\n")
    end
  end
end

def load_map(filename, sp)
  map = Hash.new
  if File.exist?(filename)
    File.open(filename, 'r') do |f|
      lines = f.readlines
      lines.each do |line|
        next if line.index('#')

        parts = line.split(sp)
        next if parts.length < 2

        map[parts[0..parts.length - 2].join(sp)] = remove_newline(parts[parts.length - 1])        
      end
    end
  end
  
  return map
end

country_map = load_map('countrymap.txt', ' ')
app_map = load_map('appmap.txt', ' ')

def get_data(store, appid)
  url = "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=#{appid}&pageNumber=0&sortOrdering=0&type=Purple+Software"
  headers = {"User-Agent" => "iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)",
    "X-Apple-Store-Front" => "#{store}-1",
    "Pragma" => "no-cache",
    "Cache-Control" => "no-cache"}

  data = ""
  open(url, headers) do |f|
    data << f.read
  end
  
  return data
end

def review_feed(data, country, app, appid)
  doc = REXML::Document.new(data)
  titles = []
  doc.elements.each("Document/View/ScrollView/VBoxView/View/MatrixView/VBoxView/VBoxView/VBoxView/HBoxView/TextView/SetFontStyle/b/") do |title|
    if title.text
      titles << remove_newline(title.text).strip
    end
  end

  stars = []
  doc.elements.each("Document/View/ScrollView/VBoxView/View/MatrixView/VBoxView/VBoxView/VBoxView/HBoxView/HBoxView/HBoxView/") do |star|
    if star
      star = star.attributes["alt"].to_s
      if star.length > 0
        stars << star
      end
    end
  end

  users = []
  doc.elements.each("Document/View/ScrollView/VBoxView/View/MatrixView/VBoxView/VBoxView/VBoxView/HBoxView/TextView/SetFontStyle/GotoURL/b/") do |user|
    if user.text
      users << remove_newline(user.text).strip
    end
  end

  versions = []
  times = []
  doc.elements.each("Document/View/ScrollView/VBoxView/View/MatrixView/VBoxView/VBoxView/VBoxView/HBoxView/TextView/SetFontStyle/") do |info|
      if info.text
        info = remove_newline(info.to_s)
        vindex = info.index("Version")
        findex = info.index("</SetFontStyle>")
        info = info[vindex, findex - vindex]
        infos = info.split('-')
        versions << infos[0].strip
        times << infos[1].strip
      end
  end

  rvs = []
  doc.elements.each("Document/View/ScrollView/VBoxView/View/MatrixView/VBoxView/VBoxView/VBoxView/TextView/SetFontStyle/") do |rv|
      if rv.text
        rvs << rv.text
      end
  end
  
  ret = ""
  i = 0;
  for user in users do
    guid = CGI.escapeHTML("#{app}:#{country}:#{users[i]}:#{titles[i]}:#{times[i]}:#{rvs[i].length}")
    ret << "<item>\n"
    ret << "<title>#{titles[i]} [#{stars[i]}][#{app}][#{country}]</title>\n"
    ret << "<link>http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=#{appid}</link>\n"
    ret << "<description>#{rvs[i]}</description>\n"
    ret << "<author>#{CGI.escapeHTML(users[i])}</author>\n"
    ret << "<category>#{app}:#{country}</category>\n"
    ret << "<pubDate>#{times[i]}</pubDate>\n"
    ret << "<guid>#{guid}</guid>\n"
    ret << "</item>\n"
    i = i + 1
  end

  return ret
end

def get_rating_diff(rating_map, country, app, rating)
  parts = rating.gsub('ratings', '').gsub('rating', '').gsub('stars', '').gsub('star', '').strip.split(',')
  return if parts.length == 0

  new_rating = nil
  old_rating = nil
  use_old = false
  key = nil
  if parts.length == 1
    key = "#{country}_#{app}_allstar"
    new_rating = parts[0].strip
  elsif parts.length == 2
    key = "#{country}_#{app}_#{parts[0].strip}_star"
    new_rating = parts[1].strip
  end

  if key and new_rating
    if rating_map[key]
      old_rating = rating_map[key]
    end
    rating_map[key] = new_rating
  end
  
  diff = 0
  if old_rating and new_rating
    diff = new_rating.to_i - old_rating.to_i
  end
  
  old_key = key + "_old"
  if diff == 0
    if rating_map[old_key]
      old_rating = rating_map[old_key]
      diff = new_rating.to_i - old_rating.to_i
      use_old = true
    end
  else
    rating_map[old_key] = old_rating
  end

  return [diff, use_old]
end

def rating_feed(data, country, app, appid, rating_map)
  doc = REXML::Document.new(data)

  ratings = []
  doc.elements.each("//HBoxView/VBoxView/VBoxView/View/View/View/VBoxView/Test/VBoxView/HBoxView/VBoxView/TextView/SetFontStyle/") do |rating|
      if rating.text
        rating = rating.text
        if rating.index("ratings")
          ratings << rating.strip
          break
        end
      end
  end

  doc.elements.each("//HBoxView/VBoxView/VBoxView/View/View/View/VBoxView/Test/VBoxView/MatrixView/VBoxView/HBoxView/") do |rating|
    ratings << rating.attributes["alt"]
  end
  
  ret = ""
  if ratings.length > 0
    diff, use_old = get_rating_diff(rating_map, country, app, ratings[0])
    
    ret << "<item>\n"
    if diff > 0 and not use_old
      ret << "<title>#{app} [#{ratings[0]} +#{diff}] [#{country}]</title>\n"
    elsif diff < 0 and not use_old
      ret << "<title>#{app} [#{ratings[0]} #{diff}] [#{country}]</title>\n"
    else
      ret << "<title>#{app} [#{ratings[0]}] [#{country}]</title>\n"
    end
    ret << "<link>http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=#{appid}</link>\n"
    
    ret << "<description>\n"
    ratings[1..ratings.length - 1].each do |rating|
      diff, use_old = get_rating_diff(rating_map, country, app, rating)

      if diff > 0 and not use_old
        ret << "<br>#{rating} +#{diff}</br>"
      elsif diff < 0 and not use_old
        ret << "<br>#{rating} #{diff}</br>"
      else
        ret << "<br>#{rating}</br>"
      end
    end
    ret << "</description>\n"
    ret << "<author>#{app}</author>\n"
    ret << "<category>#{app}</category>\n"
    ret << "<pubDate>#{Time.now}</pubDate>\n"
    ret << "<guid>#{app}:#{country}:#{ratings.join(':')}</guid>\n"
    ret << "</item>\n"
  end

  return ret
end

def get_feed(country_map, app_map)
  ret = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
  ret << "<rss version=\"2.0\" xmlns:sns=\"http://www.zhayupeng.org./appstore\">\n"
  ret << "<channel>\n"
  ret << "<title>appstore reviews</title>\n"
  ret << "<description>appstore ratings</description>\n"
  ret << "<language>en-US</language>\n"
  
  rating_map = load_map('ratingmap.txt', ',')
  app_map.each do |akey, avalue|
    country_map.each do |ckey, cvalue|
      data = get_data(cvalue, avalue)
      
      rtfeed = rating_feed(data, ckey.to_s, akey, avalue, rating_map)
      if rtfeed.length > 0
        ret << rtfeed
      end
      
      rvfeed = review_feed(data, ckey.to_s, akey, avalue)
      if rvfeed.length > 0
        ret << rvfeed
      end      
    end
  end
  save_map('ratingmap.txt', rating_map, ',')
  ret << "</channel>\n"
  ret << "</rss>\n"
  
  return ret  
end

puts get_feed(country_map, app_map)
